home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
DEMON
/
RISCOS2
/
TCP_131S.ARC
/
c
/
AX25
< prev
next >
Wrap
Text File
|
1994-03-05
|
14KB
|
380 lines
/* Low level AX.25 frame processing - address header */
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "timer.h"
#include "arp.h"
#include "slip.h"
#include "ax25.h"
#include "lapb.h"
#include "netrom.h"
#include "ip.h"
/* AX.25 broadcast address: "QST-0" in shifted ascii */
struct ax25_addr ax25_bdcst = {
'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1,
('0'<<1) | E,
};
char axbdcst[AXALEN]; /* Same thing, network format */
struct ax25_addr mycall;
int digipeat = 1; /* Controls digipeating */
int32 digisent = 0; /* Number of digipeated packets */
struct ax25mh mhlist[40]; /* mheard list - 40 entries */
/* Send IP datagrams across an AX.25 link */
int ax_send(struct mbuf *bp, struct interface *interface, int32 gateway,
char precedence, char delay, char throughput, char reliability)
{
char *hw_addr;
struct ax25_cb *axp;
struct ax25 addr;
struct ax25_addr destaddr;
struct mbuf *tbp,*bptmp;
extern int16 axwindow;
int16 ssize,len,size;
int segments,first;
throughput = throughput;
precedence = precedence;
if((hw_addr = res_arp(interface,ARP_AX25,gateway,bp)) == NULLCHAR)
return 0; /* Wait for address resolution */
if(delay || (!reliability && (interface->flags == DATAGRAM_MODE))){
/* Use UI frame */
return (*interface->output)(interface,hw_addr,interface->hwaddr,PID_IP,bp);
}
/* Reliability is needed; use I-frames in AX.25 connection */
memcpy(destaddr.call,hw_addr,ALEN);
destaddr.ssid = hw_addr[ALEN];
if((axp = find_ax25(&destaddr)) == NULLAX25)
{
/* Open a new connection */
atohax25(&addr,hw_addr,(struct ax25_addr *)interface->hwaddr);
axp = open_ax25(&addr,axwindow,(void (*)())ax_incom,NULLVFP,NULLVFP,interface,(char *)0);
if(axp == NULLAX25)
{
free_p(bp);
return -1;
}
}
/* New-style frame segmenter. Returns queue of segmented fragments,
* or original packet if small enough
* See if packet is too small to segment. Note 1-byte grace factor
* so the PID will not cause segmentation of a 256-byte IP datagram.
*/
len = len_mbuf(bp);
ssize = axp->paclen;
if((bptmp = alloc_mbuf(len+1)) == NULLBUF)
{
free_p(bp);
return -1;
}
bptmp->data[0] = PID_IP;
bptmp->cnt = 1;
bptmp->cnt += pullup(&bp,bptmp->data+1,len);
if(len <= ssize + 1)
{ /* Too small to segment */
send_ax25(axp,bptmp);
return 0;
}
len = len_mbuf(bptmp);
ssize -= 2; /* ssize now equal to data portion size */
segments = 1 + (len - 1) / ssize; /* # segments */
first = 1;
while(segments != 0){
size = min(ssize,len_mbuf(bptmp));
if((tbp = alloc_mbuf(size + 2)) == NULLBUF)
break;
tbp->data[0] = PID_SEGMENT;
tbp->data[1] = --segments;
if(first){
tbp->data[1] |= SEG_FIRST;
first = 0;
}
tbp->cnt = 2;
tbp->cnt += pullup(&bptmp,tbp->data+2,size);
send_ax25(axp,tbp);
}
return 0;
}
/* Add AX.25 link header and send packet.
* Note that the calling order here must match ec_output
* since ARP also uses it.
*/
int ax_output(struct interface *interface, char *dest, char *source,
char pid, struct mbuf *data)
{
struct mbuf *abp,*cbp;
struct ax25 addr;
/* Allocate mbuf for control and PID fields, and fill in */
if((cbp = pushdown(data,2)) == NULLBUF)
{
free_p(data);
return -1;
}
cbp->data[0] = UI;
cbp->data[1] = pid;
atohax25(&addr,dest,(struct ax25_addr *)source);
if((abp = htonax25(&addr,cbp)) == NULLBUF)
{
free_p(cbp); /* Also frees data */
return -1;
}
/* This shouldn't be necessary because redirection has already been
* done at the IP router layer, but just to be safe...
*/
if(interface->forw != NULLIF)
return (*interface->forw->raw)(interface->forw,abp);
else
return (*interface->raw)(interface,abp);
}
/* Process incoming AX.25 packets.
* After optional tracing, the address field is examined. If it is
* directed to us as a digipeater, repeat it. If it is addressed to
* us or to QST-0, kick it upstairs depending on the protocol ID.
*/
void ax_recv(struct interface *interface, struct mbuf *bp)
{
struct ax25_addr *ap;
struct mbuf *hbp;
char multicast;
int nrnodes = 0;
int mheard_entry, mheard_work;
struct ax25_addr mhcall;
time_t mheard_oldest;
char control;
struct ax25 hdr;
struct ax25_cb *axp;
struct ax25_addr ifcall;
extern struct ax25_addr nr_nodebc ;
/* Use the address associated with this interface */
memcpy(ifcall.call,interface->hwaddr,ALEN);
ifcall.ssid = interface->hwaddr[ALEN];
/* Pull header off packet and convert to host structure */
if(ntohax25(&hdr,&bp) < 0)
{
/* Something wrong with the header */
free_p(bp);
return;
}
/* mheard capture code lives here */
mheard_entry = 0; /* start at the top of the list */
mheard_work = 0; /* used for spotting oldest entry */
time(&mheard_oldest); /* preload very new! */
memcpy(&mhcall,&hdr.source,sizeof(struct ax25_addr));
mhcall.ssid &= SSID; /* remove junk */
for (mheard_work = 0; mheard_work < 40 ;mheard_work++)
{
if(memcmp(&mhlist[mheard_work].mheard_call,&mhcall,
sizeof(struct ax25_addr)) == 0)
{
mheard_entry = mheard_work; /* existing entry */
break; /* exit and update entry */
}
else
{
if(mhlist[mheard_work].mheard_time < mheard_oldest)
{
mheard_entry = mheard_work; /* oldest so far */
mheard_oldest = mhlist[mheard_work].mheard_time;
}
}
} /* loop until all parsed */
memcpy(&mhlist[mheard_entry].mheard_call,&mhcall,
sizeof(struct ax25_addr)); /* callsign */
if(hdr.ndigis > 0)
{
if(hdr.digis[0].ssid & REPEATED)
mhlist[mheard_entry].mheard_digi = 1; /* repeated */
}
else
{
mhlist[mheard_entry].mheard_digi = 0; /* directly */
}
time(&mhlist[mheard_entry].mheard_time); /* capture time */
/* end of mheard capture code */
/* Scan, looking for our call in the repeater fields, if any.
* Repeat appropriate packets.
*/
for(ap = &hdr.digis[0]; ap < &hdr.digis[hdr.ndigis]; ap++){
if(ap->ssid & REPEATED)
continue; /* Already repeated */
/* Check if packet is directed to us as a digipeater */
if(digipeat && addreq(ap,&ifcall)){
/* Yes, kick it back out */
ap->ssid |= REPEATED;
if((hbp = htonax25(&hdr,bp)) != NULLBUF){
if(interface->forw != NULLIF)
(*interface->forw->raw)(interface->forw,hbp);
else
(*interface->raw)(interface,hbp);
bp = NULLBUF;
digisent++;
}
}
free_p(bp); /* Dispose if not forwarded */
return;
}
/* Packet has passed all repeaters, now look at destination */
if(addreq(&hdr.dest,&ax25_bdcst)){
multicast = 1; /* Broadcast packet */
} else if(addreq(&hdr.dest,&ifcall)){
multicast = 0; /* Packet directed at us */
} else if(addreq(&hdr.dest,&nr_nodebc)){
nrnodes = 1 ;
} else {
/* Not for us */
free_p(bp);
return;
}
if(bp == NULLBUF){
/* Nothing left */
return;
}
/* Sneak a peek at the control field. This kludge is necessary because
* AX.25 lacks a proper protocol ID field between the address and LAPB
* sublayers; a control value of UI indicates that LAPB is to be
* bypassed.
*/
control = *bp->data & ~PF;
if(uchar(control) == UI){
char pid;
pullchar(&bp);
if(pullone(&bp,&pid) != 1)
return; /* No PID */
/* NET/ROM is very poorly layered. The meaning of the stuff
* following the PID of CF depends on what's in the AX.25 dest
* field.
*/
if(nrnodes){
if(uchar(pid) == PID_NETROM)
nr_nodercv(interface,&hdr.source,bp) ;
else /* regular UI packets to "nodes" aren't for us */
free_p(bp) ;
return ;
}
/* Handle packets. Multi-frame messages are not allowed */
switch(pid){
case PID_IP:
ip_route(bp,multicast);
break;
case PID_ARP:
arp_input(interface,bp);
break;
default:
free_p(bp);
break;
}
return;
}
/* Everything from here down is LAPB stuff, so drop anything
* not directed to us:
*/
if (multicast || nrnodes) {
free_p(bp) ;
return ;
}
/* Find the source address in hash table */
if((axp = find_ax25(&hdr.source)) == NULLAX25){
/* Create a new ax25 entry for this guy,
* insert into hash table keyed on his address,
* and initialize table entries
*/
if((axp = cr_ax25(&hdr.source)) == NULLAX25){
free_p(bp);
return;
}
axp->interface = interface;
/* Swap source and destination, reverse digi string */
axp->addr.dest = hdr.source;
axp->addr.source = hdr.dest;
if(hdr.ndigis > 0){
int i,j;
/* Construct reverse digipeater path */
for(i=hdr.ndigis-1,j=0;i >= 0;i--,j++){
axp->addr.digis[j] = hdr.digis[i];
axp->addr.digis[j].ssid &= ~(E|REPEATED);
}
/* Scale timers to account for extra delay */
axp->t1.start *= hdr.ndigis+1;
axp->t2.start *= hdr.ndigis+1;
axp->t3.start *= hdr.ndigis+1;
}
axp->addr.ndigis = hdr.ndigis;
}
if(hdr.cmdrsp == UNKNOWN)
axp->proto = V1; /* Old protocol in use */
else
axp->proto = V2;
lapb_input(axp,hdr.cmdrsp,bp);
}
/* Initialize AX.25 entry in arp device table */
/* General purpose AX.25 frame output */
int sendframe(struct ax25_cb *axp, char cmdrsp, char ctl,
struct mbuf *data)
{
struct mbuf *hbp,*cbp;
int i;
if(axp == NULLAX25 || axp->interface == NULLIF)
return -1;
/* Add control field */
if((cbp = pushdown(data,1)) == NULLBUF){
free_p(data);
return -1;
}
cbp->data[0] = ctl;
axp->addr.cmdrsp = cmdrsp;
/* Create address header */
if((hbp = htonax25(&axp->addr,cbp)) == NULLBUF){
free_p(cbp);
return -1;
}
/* The packet is all ready, now send it */
if(axp->interface->forw != NULLIF)
i = (*axp->interface->forw->raw)(axp->interface->forw,hbp);
else
i = (*axp->interface->raw)(axp->interface,hbp);
return i;
}
void axarp(void)
{
memcpy(axbdcst,ax25_bdcst.call,ALEN);
axbdcst[ALEN] = ax25_bdcst.ssid;
arp_init(ARP_AX25,AXALEN,PID_IP,PID_ARP,axbdcst,psax25,setpath);
}